﻿
namespace SwtorCalculator {
    using System;

    /// <summary>
    /// /tbl/pkgattributestable
    /// /tbl/chrclassattributebonustable
    /// </summary>
    internal abstract class Stats {
        /// <summary>
        /// Character Buff Bbject
        /// </summary>
        private Buff _buffs;

        #region "Stat Mods Using /tbl/chrclassattributemappings"
        /* From Primary Stats */

        /// <summary>
        /// Bonus Damage Multiplier
        /// </summary>
        protected const double BONUS_DMG_MOD = 0.28000000000000003;

        /// <summary>
        /// Bonus Crit Divisor
        /// </summary>
        protected const double BONUS_CRIT_MOD = 2.5;

        /// <summary>
        /// Bonus Healing Multiplier
        /// </summary>
        protected const double BONUS_HEAL_MOD = 0.24;

        /* From Gear Stats */

        /// <summary>
        /// Bonus Health Multiplier
        /// </summary>
        protected const int HEALTH_MOD = 10;

        /// <summary>
        /// Bonus Attack Power Multiplier
        /// </summary>
        protected const double POWER_ATK_MOD = 0.15;

        /// <summary>
        /// Bonus Healing Multiplier
        /// </summary>
        protected const double POWER_HEAL_MOD = 0.12;

        /// <summary>
        /// Crit Rating Divisor
        /// </summary>
        protected const double CRIT_RATING_MOD = 0.5;

        /// <summary>
        /// Accuracy Divisor
        /// </summary>
        protected const double ACCURACY_MOD = 0.08;

        /// <summary>
        /// Surge Divisor
        /// </summary>
        protected const double SURGE_MOD = 0.05;

        /// <summary>
        /// Spell Haste Divisor
        /// </summary>
        protected const double SPELL_HASTE_MOD = 0.05;

        /// <summary>
        /// Defense Divisor
        /// </summary>
        protected const double DEFENSE_MOD = 0.08;

        /* From Presence */

        /// <summary>
        /// Companion Health Bonus Divisor
        /// </summary>
        protected const int COMP_HEALTH_BONUS = 2; // UNCONFIRMED

        /// <summary>
        /// Companion Bonus Damage Divisor
        /// </summary>
        protected const int COMP_DMG_BONUS = 20; // UNCONFIRMED

        /// <summary>
        /// Companion Bonus Healing Divisor
        /// </summary>
        protected const int COMP_HEAL_BONUS = 5; // UNCONFIRMED
        #endregion

        /// <summary>
        /// Initializes a New Instance of the Stats Class
        /// </summary>
        internal Stats() {
            _buffs = new Buff();
        }

        /// <summary>
        /// Gets or Sets the Buff Object
        /// </summary>
        internal Buff Buffs {
            get { return _buffs; }
            private set {
                if( value != null )
                    _buffs = value;
            }
        }

        #region "Base Stats"
        /// <summary>
        /// Gets or Sets the Characters Current Level
        /// </summary>
        internal int Level { get; set; }

        /// <summary>
        /// Gets the Characters Base Strength
        /// </summary>
        internal virtual int StrengthBase { get { return getTrivialStat(); } }

        /// <summary>
        /// Gets or Sets the Characters Strength From Gear
        /// </summary>
        internal int StrengthGear { get; set; }

        /// <summary>
        /// Gets the Characters Total Strength
        /// </summary>
        internal int StrengthTotal {
            get { return ( int )Math.Floor( ( StrengthBase + StrengthGear + Buffs.MightStim_Stat ) * Buffs.UnearthedPower_Stats ); }
        }

        /// <summary>
        /// Gets the Characters Base Aim
        /// </summary>
        internal virtual int AimBase { get { return getTrivialStat(); } }

        /// <summary>
        /// Gets or Sets the Characters Aim From Gear
        /// </summary>
        internal int AimGear { get; set; }

        /// <summary>
        /// Gets the Characters Total Aim
        /// </summary>
        internal int AimTotal {
            get { return ( int )Math.Floor( ( AimBase + AimGear + Buffs.ReflexStim_Stat ) * Buffs.UnearthedPower_Stats ); }
        }

        /// <summary>
        /// Gets the Characters Base Cunning
        /// </summary>
        internal virtual int CunningBase { get { return getTrivialStat(); } }

        /// <summary>
        /// Gets or Sets the Characters Cunning From Gear
        /// </summary>
        internal int CunningGear { get; set; }

        /// <summary>
        /// Gets the Characters Total Cunning
        /// </summary>
        internal int CunningTotal {
            get { return ( int )Math.Floor( ( CunningBase + CunningGear + Buffs.SkillStim_Stat ) * Buffs.UnearthedPower_Stats ); }
        }

        /// <summary>
        /// Gets the Characters Base Willpower
        /// </summary>
        internal virtual int WillpowerBase { get { return getTrivialStat(); } }

        /// <summary>
        /// Gets or Sets the Characters Willpower From Gear
        /// </summary>
        internal int WillpowerGear { get; set; }

        /// <summary>
        /// Gets the Characters Total Willpower
        /// </summary>
        internal int WillpowerTotal {
            get { return ( int )Math.Floor( ( WillpowerBase + WillpowerGear + Buffs.ResolveStim_Stat ) * Buffs.UnearthedPower_Stats ); }
        }

        /// <summary>
        /// Gets the Characters Base Endurance
        /// (Secondary Stat)
        /// </summary>
        internal int EnduranceBase { get { return getSecondaryStat(); } }

        /// <summary>
        /// Gets or Sets Endurance From Gear
        /// </summary>
        internal int EnduranceGear { get; set; }

        /// <summary>
        /// Gets the Characters Total Endurance
        /// </summary>
        internal int EnduranceTotal {
            get { return (int)Math.Floor( (double)( EnduranceBase + EnduranceGear + Buffs.FortStim_Stat ) * Buffs.FortifiedSerum ); }
        }

        /// <summary>
        /// Gets the Characters Base Presence
        /// (Secondary Stat)
        /// </summary>
        internal int PresenceBase { get { return getSecondaryStat(); } }

        /// <summary>
        /// Gets or Sets the Characters Presence From Gear
        /// </summary>
        internal int PresenceGear { get; set; }

        /// <summary>
        /// Gets the Characters Total Presence
        /// </summary>
        internal int PresenceTotal { get { return PresenceBase + PresenceGear + Buffs.CommandStim_Stat; } }

        /// <summary>
        /// Gets the Characters Bonus Hit Points from Stats
        /// </summary>
        internal int BaseHealthPoint { get { return EnduranceTotal * HEALTH_MOD; } }
        #endregion

        #region "Damage Formulas"
        /// <summary>
        /// Gets or Sets the Characters Power Stat
        /// </summary>
        internal int Power { get; set; }

        /// <summary>
        /// Gets the Characters Bonus Damage From Gear and Buffs
        /// </summary>
        internal int PowerGear { get { return ( int )Math.Floor( ( Power + Buffs.BattleAttackAverage + Buffs.ReflexStim_Second +
                                Buffs.SkillStim_Second + Buffs.MightStim_Second + Buffs.ResolveStim_Second ) * POWER_ATK_MOD ); } }

        /// <summary>
        /// Gets or Sets the Characters Force Power Stat
        /// </summary>
        internal int ForcePower { get; set; }

        /// <summary>
        /// Gets the Characters Bonus Force Damage From Gear and Buffs
        /// </summary>
        internal int ForcePowerGear { get { return ( int )Math.Floor( ( ForcePower + Buffs.BattleForceAverage ) * POWER_ATK_MOD ); } }

        /// <summary>
        /// Gets or Sets the Characters Tech Power Stat
        /// </summary>
        internal int TechPower { get; set; }

        /// <summary>
        /// Gets the Characters Bonus Tech Damage From Gear and Buffs
        /// </summary>
        internal int TechPowerGear { get { return ( int )Math.Floor( ( TechPower + Buffs.BattleTechAverage ) * POWER_ATK_MOD ); } }

        /// <summary>
        /// Gets the Characters Bonus Melee Damage From Stats
        /// </summary>
        internal virtual int MeleeBonusStats { get { return ( int )Math.Floor( ( double )StrengthTotal * BONUS_DMG_MOD ); } }

        /// <summary>
        /// Gets the Characters Total Bonus Melee Damage
        /// </summary>
        internal int MeleeBonusTotal {
            get { return (int)Math.Floor( ( MeleeBonusStats + PowerGear ) * Buffs.UnearthedMight ); }
        }

        /// <summary>
        /// Gets the Characters Bonus Range Damage From Stats
        /// </summary>
        internal virtual int RangeBonusStats { get { return (int)Math.Floor( ( double )AimTotal * BONUS_DMG_MOD ); } }

        /// <summary>
        /// Gets the Characters Total Bonus Range Damage
        /// </summary>
        internal int RangeBonusTotal {
            get { return (int)Math.Floor( ( RangeBonusStats + PowerGear ) * Buffs.UnearthedMight ); }
        }

        /// <summary>
        /// Gets the Characters Bonus Tech Damage From Stats
        /// </summary>
        internal virtual int TechBonusStats { get { return (int)Math.Floor( ( double )CunningTotal * BONUS_DMG_MOD ); } }

        /// <summary>
        /// Gets the Characters Total Bonus Tech Damage
        /// </summary>
        internal int TechBonusTotal {
            get { return (int)Math.Floor( ( TechBonusStats + TechPowerGear + PowerGear ) * Buffs.UnearthedMight); }
        }

        /// <summary>
        /// Gets the Characters Bonus Force Damage From Stats
        /// </summary>
        internal virtual int ForceBonusStats { get { return (int)Math.Floor( (double)WillpowerTotal * BONUS_DMG_MOD ); } }

        /// <summary>
        /// Gets the Characters Total Bonus Force Damage
        /// </summary>
        internal int ForceBonusTotal {
            get { return (int)Math.Floor( ( ForceBonusStats + ForcePowerGear + PowerGear ) * Buffs.UnearthedMight ); }
        }
        #endregion

        #region "Crit Formulas"
        /// <summary>
        /// Gets the Characters Base Crit Chance
        /// </summary>
        internal double CritBase { get { return .1; } }

        /// <summary>
        /// Gets or Sets the Characters Crit Rating Stat
        /// </summary>
        internal int CritGearStat { get; set; }

        /// <summary>
        /// Gets the Characters Crit Rating From Gear and Buffs
        /// </summary>
        internal double CritGear { get { return Math.Round( ( ( double )( CritGearStat + Buffs.BattleCriticalAverage ) / CRIT_RATING_MOD ) / 10000, 4 ); } }

        /// <summary>
        /// Gets the Characters Melee Crit Chance From Stats
        /// </summary>
        internal virtual double MeleeCritStats { get { return Math.Round( ( ( double )StrengthTotal / BONUS_CRIT_MOD ) / 10000, 4 ); } }

        /// <summary>
        /// Gets the Characters Total Melee Crit Chance
        /// </summary>
        internal double MeleeCritTotal {
            get { return CritBase + MeleeCritStats + CritGear + Buffs.CriticalSerum; }
        }

        /// <summary>
        /// Gets the Characters Range Crit Chance From Stats
        /// </summary>
        internal virtual double RangeCritStats { get { return Math.Round( ( ( double )AimTotal / BONUS_CRIT_MOD ) / 10000, 4 ); } }

        /// <summary>
        /// Gets the Characters Total Range Crit Chance
        /// </summary>
        internal double RangeCritTotal {
            get { return CritBase + RangeCritStats + CritGear + Buffs.CriticalSerum; }
        }

        /// <summary>
        /// Gets the Characters Tech Crit Chance From Stats
        /// </summary>
        internal virtual double TechCritStats { get { return Math.Round( ( ( double )CunningTotal / BONUS_CRIT_MOD ) / 10000, 4 ); } }

        /// <summary>
        /// Gets the Characters Total Tech Crit Chance
        /// </summary>
        internal double TechCritTotal {
            get { return CritBase + TechCritStats + CritGear + Buffs.CriticalSerum; }
        }

        /// <summary>
        /// Gets the Characters Force Crit Chance From Stats
        /// </summary>
        internal virtual double ForceCritStats { get { return Math.Round( ( ( double )WillpowerTotal / BONUS_CRIT_MOD ) / 10000, 4 ); } }

        /// <summary>
        /// Gets the Characters Total Force Crit Chance
        /// </summary>
        internal double ForceCritTotal {
            get { return CritBase + ForceCritStats + CritGear + Buffs.CriticalSerum; }
        }

        /// <summary>
        /// Gets or Sets the Characters Surge Stat
        /// </summary>
        internal int SurgeStat { get; set; }

        /// <summary>
        /// Gets the Characters Bonus Crit Damage
        /// </summary>
        internal double SurgeGear {
            get { return Math.Round( ( ( double )SurgeStat / SURGE_MOD ) / 10000, 4 ); }
        }

        internal double CritDmgTotal {
            get { return .5 + SurgeGear; }
        }
        #endregion

        #region "Hit/Haste/Pen Formulas"
        /// <summary>
        /// Gets the Characters Base Hit Percent
        /// </summary>
        internal double AccuracyBase { get { return 1 - ( Character.isDualWield ? .33 : 0 ); } }
        
        /// <summary>
        /// Gets or Sets the Characters Accuracy Stat
        /// </summary>
        internal int AccuracyStat { get; set; }

        /// <summary>
        /// Gets the Characters Hit Percent
        /// </summary>
        internal double HitGear { get { return Math.Round( ( ( double )AccuracyStat / ACCURACY_MOD ) / 10000, 4 ); } }

        /// <summary>
        /// Gets the Characters Total Hit Percent
        /// </summary>
        internal double HitTotal { get { return ( AccuracyBase + HitGear > 1 ? 1 : AccuracyBase + HitGear ); } }

        /// <summary>
        /// Gets the Characters Armor Penetration Percent
        /// </summary>
        internal double ArPenGear { get { return Math.Round( ( ( double )AccuracyStat / ACCURACY_MOD ) / 10000, 4 ); } }

        /// <summary>
        /// Gets the Characters Total Armor Penetration Percent
        /// </summary>
        internal double ArPenTotal { get { return Buffs.ArPenCell + ( AccuracyBase + HitGear > 1 ? ( ( AccuracyBase + HitGear ) - 1 ) : 0 ); } }

        /// <summary>
        /// Gets the Characters Spell Penetration Percent
        /// </summary>
        internal double SpellPenGear { get { return Math.Round( ( ( double )AccuracyStat / ACCURACY_MOD ) / 10000, 4 ); } }

        /// <summary>
        /// Gets the Characters Total Spell Penetration Percent
        /// </summary>
        internal double SpellPenTotal { get { return ( AccuracyBase + HitGear > 1 ? ( ( AccuracyBase + HitGear ) - 1 ) : 0 ); } }

        /// <summary>
        /// Gets or Sets the Characters Alacrity Stat
        /// </summary>
        internal int AlacrityStat { get; set; }

        /// <summary>
        /// Gets the Characters Spell Haste Percent
        /// </summary>
        internal double AlacrityGear { get { return Math.Round( ( ( double )AlacrityStat / SPELL_HASTE_MOD ) / 10000, 4 ); } }
        #endregion

        #region "Defense Formulas"
        /// <summary>
        /// Gets or Sets the Characters Armor
        /// Affects Kinetic and Energy damage reduction
        /// </summary>
        internal double ArmorStat { get; set; }

        /// <summary>
        /// Gets the Characters Total Armor
        /// </summary>
        internal double ArmorTotal { get { return ( ArmorStat + Buffs.BattleAbsorbAverage ) * Buffs.TankForm_Armor * Buffs.TankCell_Armor * Buffs.TankCharge_Armor; } }

        /// <summary>
        /// Gets the Characters Damage Reduction From Armor : 
        /// Thanks to Anubis Black and Masterkiller @ sithwarrior.com
        /// </summary>
        internal double ArmorReductionBonus {
            get { return ( ArmorTotal / ( ArmorTotal + ( 200 * Level ) + 800 ) ); }
        }
        
        /// <summary>
        /// Gets the Characters Current Kinetic Damage Reduction
        /// </summary>
        internal double KineticReduction {
            get { return .05 + ArmorReductionBonus + Buffs.TankForm_Reduction + Buffs.BalanceForm_Reduction + Buffs.TankCell_Reduction; }
        }

        /// <summary>
        /// Gets the Characters Current Energy Damage Reduction
        /// </summary>
        internal double EnergyReduction {
            get { return .05 + ArmorReductionBonus + Buffs.TankForm_Reduction + Buffs.BalanceForm_Reduction + Buffs.TankCell_Reduction; }
        }

        /// <summary>
        /// Gets the Characters Current Internal Damage Reduction
        /// </summary>
        internal double InternalReduction {
            get { return .05 + Buffs.UnearthedPower_Reduction + Buffs.TankForm_Reduction + Buffs.BalanceForm_Reduction + Buffs.TankCell_Reduction; }
        }

        /// <summary>
        /// Gets the Characters Current Elemental Damage reduction
        /// </summary>
        internal double ElementalReduction {
            get { return .05 + Buffs.UnearthedPower_Reduction + Buffs.TankForm_Reduction + Buffs.BalanceForm_Reduction + Buffs.TankCell_Reduction; }
        }

        /// <summary>
        /// Gets or Sets the Characters Defense Stat
        /// </summary>
        internal int DefenseStat { get; set; }

        /// <summary>
        /// Gets the Characters Total Defense
        /// </summary>
        internal int DefenseTotal {
            get { return DefenseStat + Buffs.FortStim_Second; }
        }

        /// <summary>
        /// Gets the Characters Parry Chance
        /// </summary>
        internal double ParryGear { get { return Math.Round( ( (double)DefenseTotal / DEFENSE_MOD ) / 10000, 4 ); } }

        /// <summary>
        /// Gets the Characters Deflect Chance
        /// </summary>
        internal double DeflectGear { get { return Math.Round( ( ( double )DefenseTotal / DEFENSE_MOD ) / 10000, 4 ); } }

        /// <summary>
        /// Gets or Sets the Characters Shield Stat
        /// </summary>
        internal int ShieldStat { get; set; }

        /// <summary>
        /// Gets the Characters Shield [Block] Chance from Gear
        /// </summary>
        internal double ShieldGear { get { return Math.Floor( ( (double)ShieldStat * 0 /*Some Mod*/ ) * 100 ) / 100; } }

        /// <summary>
        /// Gets the Characters Total Shield Chance
        /// </summary>
        internal double ShieldChanceTotal {
            get { return ShieldGear + Buffs.TankForm_Shield + Buffs.TankCell_Shield + Buffs.TankCharge_Sheild; }
        }

        /// <summary>
        /// Gets or Sets the Characters Absorption Stat
        /// </summary>
        internal double AbsorptionStat { get; set; }

        /// <summary>
        /// Gets the Characters Absorption Percent
        /// </summary>
        internal double AbsorptionGear { get { return Math.Floor( ( (double)AbsorptionStat * 0 /*Some Mod*/ ) * 100 ) / 100; } }
        #endregion

        #region "Companion Formulas"
        /// <summary>
        /// Gets the Companions Bonus Hit Points From Player Stats
        /// UNCONFIRMED
        /// </summary>
        internal int CompanionHealthBonus { get { return (int)Math.Floor( ( double )PresenceBase / COMP_HEALTH_BONUS ); } }

        /// <summary>
        /// Gets the Companions Bonus Damage From Player Stats
        /// UNCONFIRMED
        /// </summary>
        internal int CompanionDmgBonus { get { return (int)Math.Floor( ( double )PresenceBase / COMP_DMG_BONUS ); } }

        /// <summary>
        /// Gets the Companions Bonus Healing From Player Stats
        /// UNCONFIRMED
        /// </summary>
        internal int CompanionHealBonus { get { return ( int )Math.Floor( ( double )PresenceBase / COMP_HEAL_BONUS ); } }
        #endregion

        #region "Stat Calculations"
        /// <summary>
        /// Gets the Primary Stat Given the Characters Level
        /// </summary>
        /// <returns>Primary Stat Amount</returns>
        protected int getPrimaryStat() {
            return 50 + ( Level * 4 );
        }

        /// <summary>
        /// Calculates the Secondary Stat Given the Characters Level
        /// </summary>
        /// <returns>Secondary Stat Amount</returns>
        protected int getSecondaryStat() {
            return (int)Math.Floor( 45 + ( Level * 3.6 ) );
        }

        /// <summary>
        /// Calculates the Weak Stat Given the Characters Level
        /// </summary>
        /// <returns>Weak Stat Amount</returns>
        protected int getWeakStat() {
            return (int)Math.Floor( 20 + ( Level * 1.6 ) );
        }

        /// <summary>
        /// Calculates the Trivial Stat Given the Characters Level
        /// </summary>
        /// <returns>Trivial Stat Amount</returns>
        protected int getTrivialStat() {
            return Level + 10 - (int)Math.Ceiling( (double)Level / 5 );
        }
        #endregion
    }
}